/* ESPNOW Example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/

/*
   This example shows how to use ESPNOW.
   Prepare two device, one for sending ESPNOW data and another for receiving
   ESPNOW data.
*/
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <assert.h>
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/timers.h"
#include "nvs_flash.h"
#include "esp_event_loop.h"
#include "tcpip_adapter.h"
#include "esp_wifi.h"
#include "esp_log.h"
#include "esp_system.h"
#include "esp_now.h"
#include "rom/ets_sys.h"
#include "rom/crc.h"
#include "main.h"


#include "esp_sleep.h"

static const char *TAG = "espnow_example";
#define CONFIG_ESPNOW_PMK "pmk1234567890123"
#define CONFIG_ESPNOW_LMK "lmk1234567890123"

static uint8_t broadcast_mac_addr[ESP_NOW_ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };

uint8_t sendbuffer[128] = {0};

/* WiFi should start before using ESPNOW */
static void example_wifi_init(void)
{
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
    ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
    ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
    ESP_ERROR_CHECK( esp_wifi_start());

    ESP_ERROR_CHECK( esp_wifi_set_channel(1, 0) );
}

static void example_espnow_send_cb(const uint8_t *mac_addr, esp_now_send_status_t status)
{
    if (mac_addr == NULL) {
        ESP_LOGE(TAG, "Send cb arg error");
        return;
    }

    if (status == ESP_NOW_SEND_SUCCESS) {
        printf("esp now send to "MACSTR" success\n", MAC2STR(mac_addr));
    } else {
        printf("esp now send to "MACSTR" fail\n", MAC2STR(mac_addr));
    }
}

static void example_espnow_recv_cb(const uint8_t *mac_addr, const uint8_t *data, int len)
{
    if (mac_addr == NULL || data == NULL || len <= 0) {
        ESP_LOGE(TAG, "Receive cb arg error");
        return;
    }

    printf("esp now recb %d Byte data form "MACSTR"\n", len, MAC2STR(mac_addr));
    printf("%.*s\n\n", len, data);
	esp_wifi_stop();
}

static void example_espnow_task(void *argv)
{
    int num = 0;
    ESP_LOGI(TAG, "Start sending broadcast data");
    while (1) {
        snprintf((char *)sendbuffer, sizeof(sendbuffer), "this is a broadcast %d", num++);
        if (esp_now_send(broadcast_mac_addr, sendbuffer, strlen((char *)sendbuffer)) != ESP_OK) {
            ESP_LOGE(TAG, "Send error");
            vTaskDelete(NULL);
        }
        vTaskDelay(5000/portTICK_RATE_MS);
    }
}

static esp_err_t example_espnow_init(void)
{

    ESP_ERROR_CHECK( esp_now_init() );
    ESP_ERROR_CHECK( esp_now_register_send_cb(example_espnow_send_cb) );
    ESP_ERROR_CHECK( esp_now_register_recv_cb(example_espnow_recv_cb) );

    /* Set primary master key. */
    // ESP_ERROR_CHECK( esp_now_set_pmk((uint8_t *)CONFIG_ESPNOW_PMK) );

    // /* Add broadcast peer information to peer list. */
    // esp_now_peer_info_t *peer = malloc(sizeof(esp_now_peer_info_t));
    // if (peer == NULL) {
    //     ESP_LOGE(TAG, "Malloc peer information fail");
    //     esp_now_deinit();
    //     return ESP_FAIL;
    // }

    // memset(peer, 0, sizeof(esp_now_peer_info_t));
    // peer->channel = 1;
    // peer->ifidx = ESP_IF_WIFI_STA;
    // peer->encrypt = false;
    // memcpy(peer->peer_addr, broadcast_mac_addr, ESP_NOW_ETH_ALEN);
    // ESP_ERROR_CHECK( esp_now_add_peer(peer) );
    // free(peer);

    // xTaskCreate(example_espnow_task, "example_espnow_task", 2048, NULL, 4, NULL);

    return ESP_OK;
}

void app_main()
{
    tcpip_adapter_init();

    ESP_ERROR_CHECK(esp_event_loop_create_default());

    example_wifi_init();
    example_espnow_init();

    esp_wifi_set_ps(WIFI_PS_MAX_MODEM);

    esp_pm_config_esp8266_t pm_config = {
            .light_sleep_enable = true
    };
    ESP_ERROR_CHECK( esp_pm_configure(&pm_config) );

	while (1) {
		vTaskDelay(60/portTICK_RATE_MS);
		ESP_LOGW(TAG, "esp_wifi_stop");
		esp_wifi_stop();
		vTaskDelay(500/portTICK_RATE_MS);
		ESP_LOGI(TAG, "esp_wifi_start");
		esp_wifi_start();
    	example_espnow_init();
	}

	// esp_deep_sleep(5000 * 1000); 	// 深度休眠，自动唤醒需要连接GPIO16 -> RST
}
